package com.wang.designpattern.singleton;

import org.apache.commons.lang3.SerializationUtils;

import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

/**
 * 饿汉式单例模式测试
 */
public class Singleton01Test {

    public static void main(String[] args) {
        MyThread1 mt1 = new MyThread1("线程A ") ;    // 实例化对象
        MyThread1 mt2 = new MyThread1("线程B ") ;    // 实例化对象
        Thread t1 = new Thread(mt1) ;       // 实例化Thread类对象
        Thread t2 = new Thread(mt2) ;       // 实例化Thread类对象
        t1.start() ;    // 启动多线程
        t2.start() ;    // 启动多线程
        try {
            // 通过反射攻击单例模式
            Constructor<Singleton01> constructor = Singleton01.class.getDeclaredConstructor();
            constructor.setAccessible(true);
            Singleton01 newInstance = constructor.newInstance();
            System.out.println("反射 newInstance : " + newInstance.hashCode());
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

        // 通过反序列化攻击单例模式
        Singleton01 instance = Singleton01.getInstance();
        byte[] serialize = SerializationUtils.serialize(instance);
        Singleton01 newInstance = SerializationUtils.deserialize(serialize);
        System.out.println("反序列化 instance : " + instance.hashCode());
        System.out.println("反序列化 newInstance : " + newInstance.hashCode());
    }
}
class Singleton01 implements Serializable {
    private Singleton01() {}

    private static final Singleton01 instance = new Singleton01();

    public static Singleton01 getInstance() {
        return instance;
    }
}

class MyThread1 implements Runnable{ // 实现Runnable接口，作为线程的实现类
    private String name ;       // 表示线程的名称
    public MyThread1(String name){
        this.name = name ;      // 通过构造方法配置name属性
    }
    public void run(){  // 覆写run()方法，作为线程 的操作主体、
        if (name.equals("线程A ")) {
            try {
                Thread.sleep(1000L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        Singleton01 singleton = Singleton01.getInstance();
        System.out.println(name +  " " + singleton.hashCode());
    }
}